#pragma once
// 单生产者对单消费者
#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "mutex.hpp"
using namespace std;
static int gcap = 5;
template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = gcap):
    _cap(cap), _ring_queue(cap), _space_sem(cap), _data_sem(0), _p_step(0), _c_step(0)
    {
    }
    // 怎么理解这个Pop和Enqueue的逻辑
    // 信号量的本质是对资源的预定机制
    // 1.单生产者和单消费者的情况下用不用加锁
    // 答案是不用 这个队列是一个环形队列 队列有三种情况 除去生产者和消费在同一位置的情况下 还有一种情况就是
    // 生产者和消费者在访问不同的资源所以此时当然不需要加锁了，因为没有访问共同资源
    void Pop(T *out)
    {
        _data_sem.p();
        {
            *out = _ring_queue[_c_step++];
            _c_step %= _cap;
            _space_sem.v();
        }
    }
    void Enqueue(const T &in)
    {
        _space_sem.p();
        {
            //生产者申请信号量如果为满的话 此时的信号量就为0就会阻塞住，让消费者先消费，间接实现了两者的互斥，反正依然
            _ring_queue[_p_step++] = in;
            _p_step %= _cap;
            _data_sem.v();
        }
    }
    ~RingQueue()
    {
    }

private:
    vector<T> _ring_queue; // 临界资源 访问这个临界资源有2种情况
    // 第一种生产者和消费者在队列的同一位置访问数据，然后又分为两者情况一种是队列此时是满的—>此时让消费者先出队列
    // 还有一种情况是 队列是空的->此时要先让生产者先入队列
    // 第二种情况是 生产者和消费者不在用一个位置，此时两者互相不影响
    //第一种情况怎么实现互斥呢，引入了两个信号量 分别为消费者和生产的信号量
    int _cap;
    Sem _space_sem;
    Sem _data_sem;

    // 生产者和消费者的当前位置.  解决生产数据了有空间如何放哪里的问题
    int _p_step;
    int _c_step;
};